package com.yuantu.judiciary.serviceimpl;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.DatadigitalFincloudGeneralsaasFaceCertifyInitializeRequest;
import com.alipay.api.request.DatadigitalFincloudGeneralsaasFaceCertifyQueryRequest;
import com.alipay.api.request.DatadigitalFincloudGeneralsaasFaceCertifyVerifyRequest;
import com.alipay.api.response.DatadigitalFincloudGeneralsaasFaceCertifyInitializeResponse;
import com.alipay.api.response.DatadigitalFincloudGeneralsaasFaceCertifyQueryResponse;
import com.alipay.api.response.DatadigitalFincloudGeneralsaasFaceCertifyVerifyResponse;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.yuantu.judiciary.dao.*;
import com.yuantu.judiciary.exception.enums.AuthExceptionEnum;
import com.yuantu.judiciary.exception.enums.CheckPersonExceptionEnum;
import com.yuantu.judiciary.exception.enums.OrganizationExceptionEnum;
import com.yuantu.judiciary.exception.enums.SmsExceptionEnum;
import com.yuantu.judiciary.model.domain.*;
import com.yuantu.judiciary.model.dto.AuthorizedInfoDTO;
import com.yuantu.judiciary.model.enums.*;
import com.yuantu.judiciary.model.form.GetQueryInfoForm;
import com.yuantu.judiciary.model.vo.CheckPersonReportVO;
import com.yuantu.judiciary.service.*;
import com.yuantu.judiciary.utils.AssertUtil;
import com.yuantu.judiciary.utils.Sm2Util;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import java.sql.Timestamp;

/**
 * 阿里外部接口实现
 *
 * @author syw
 * @since 2023-07-08
 **/
@Service
@RequiredArgsConstructor
@Slf4j
public class ApiAliAuthServiceImpl implements IApiAliAuthService {

    String privateKey = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCTHb+LMi7v7Et7tGWcV3UFRIk/BO2zE/sZsbrtBwzDgNECRI5AT/VZfzWfLFdFp3t43EWOZkUWZN7BK+zp4hw625FpWbintwBBSqiVkN0QiAG1noZqst+Uzkr4IK987VFz4QVsitJUXYKHQmV5qTyfOuxLsn1Fr80kDqJEGBCVEsLQ5eWxVmk/tk9yzoAEkRgXcD+qsPbi5FqkzDBHDAxwQQAAkUVYp+qqPG5DmEMI/bJPYrFePCHDflMdz52b50nzvbF8vmoP89nKOxrWM8Po0cfnZ3zR/RCemJhBOS5gWEwyI8uWYLK0yoUEf5qvytZLvwQumrEeCErevsS7BHI3AgMBAAECggEBAIwKaFgniBipFV2HZqZBdkpyaDdOCLtMDN3zml2hNVwxFkSTX9oGgyYTesavXdAXUujEvY2E+sULdiPqHVax/29jrXLcjnNQN3TvjbT6NgVTglURtyCAb2ZmTWUPMB26hqvJCvG83+ShMuxwnsoF+IgWffK80JTyeVOWfo5VXguYYqyi5n66g0mR+ybEiZAIHej4SWFr2wpvULSPYnu/JRfcpv0flBmcuo+VRDX2Rtqtvu4427aPYnuQyxP7TekNpu8uH1/dU/SHY+9sseadq/+2Jo2miD3j6NXJs5ahpzal94Si4g2/Ke8gvdXzxX3eZqNwfXOISKMkAq29LPx3zvkCgYEA0gVi24tQaanG/LP81uV0ulteYK3nO30vS9+Bkutd5XANSxVJyn5zEuQbOME4WjG1mOC0PEhljLhHg4NaBq6FR0MiTEDkBCbfZTStN90Ft4Jfs6hyjK4umw5ff+6HigT0N+b8Fb00XRkch0w1wHVKxzeBP/iPdvFeaiWSJ2oqBz0CgYEAs1LdeSBgfWRZveLSGjq9x5CarHx7OJMtX4uj64nWqtf/FmZazGnr8lny0sXW0JS4NswoOOevZ8pA9u/S7N3Q1tklUEGqOznWG7bgaF2/Ud8ovlKPISBWnsn0JDne3BPvYLHyia3iSYJ5DjFaYTZRs/9QCTETVto5hfp7ngCploMCgYEAvZT9Gv9UFD2ckUqMBxRT3VFTDWSN4eZsBkp4tb3fIZiXd1p9JNwmVjww0negvdI3ggv8xpn3iSJj87RjVLq/NofEcx70dUb9y2bUoiPS4EdAynVZCeLF0VQVIu+XzCASsE/C6IDFvvBHD17c+qEmYlSZSLzADHdvadQGbavoymUCgYAf/p/vVZyBot70Jz0PWv2zVpSSQ9+EV5YX3wVPKBe6AbHMoFSA9kEXy36sponOS0qW1FQ02vmLziVLKbz7cBQr0TB8IksqKAaQiU9+r4NMK0HMu1Q4N9ncmPHLaNvfblseaIF6mSCvtuy8YIfcomFveRUhnrTxoRv0UJ2vsjSP2wKBgEgMBm2srYFRgpFsB5KeXNgpcLlswLczJf8EVPt5c6k1uwDw+lpK9Kk25dMO/fnKa61FXA17gsc+dGu+p+ppyYCTX6oYQmB11yx7f/pOpFDk2IEclmYPMf2V9aT10LdD6p5GDCrfVrPku7dFWAtAzl4wJrF6cSLlHl4ZI1U1cF/a";
    String publicKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAi/7rUBi4mm2rHzSW0BLey52A69zvbXiE7gz0bvqSKKJSSpLdvBZxhseQBSuUoaOSNzmna5ov1uu0pYC1vWGHsf7YjzcrAl8aYBL+wpVAsjij+fLTeftYleVZZPjIZfGtrggDuO3L4vVrmyszOqRFS9063jy4xnfYsBwXJjmaw2vmXx6BFE+WKAmytgcopk44Jt9HZqezRtV0HcuMnBYfXW1s/9/blqNpphzpk8tWBeb9/kE0gZ2+SkLqU2Gpnn/ImeOWRs5yDKYAOYDec8AAABPGo6F3MRNAX2OSkhce1lnZV9VQvwiotbg5Az8IftwYWVyTXPqOfv/++kj5psyPnQIDAQAB";
    String appId = "2021004103655111";
    AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do", appId, privateKey, "json", "GBK", publicKey, "RSA2");

    private static final Gson GSON = new Gson();
    private final IQueryRecordDao queryRecordDao;
    private final IQueryAuthorizationDao queryAuthorizationDao;
    private final ISmsRecordDao smsRecordDao;
    private final IAuthInfoDao authInfoDao;
    private final IOrganizationDao organizationDao;
    private final IApiAliOpenService openService;
    private final ICheckPersonService checkPersonService;
    private final ISmsService smsService;
    private final IAccountDao accountDao;
    private final IUserInfoDao userInfoDao;
    private final IVipOrderDao vipOrderDao;
    private final IOperatorService operatorService;
    private final IAuthSmsLogDao authSmsLogDao;


    @Override
    public String getEncryptionParam(String sign) {
        if (StringUtils.isBlank(sign)) {
            log.info("获取签名异常，签名为空！！！");
            return "";
        }
        SmsRecordDO smsRecord = smsRecordDao.findByRemarksAndDeletedFalse(sign);
        AssertUtil.assertTrue(!ObjectUtils.isEmpty(smsRecord), SmsExceptionEnum.SMS_RECORD_NOT_EXIST);
        return Sm2Util.encrypt(smsRecord.getContent());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String getVerifyUrl(String sign) {
        if (StringUtils.isBlank(sign)) {
            log.info("获取签名异常，签名为空！！！");
            return "";
        }
        Timestamp currentTime = new Timestamp(System.currentTimeMillis());
        String res;
        // 校验查询记录
        AuthorizedInfoDTO authorizedInfo = JSON.parseObject(Sm2Util.decrypt(sign), AuthorizedInfoDTO.class);
        if (AuthType.QUERY.equals(authorizedInfo.getAuthType())) {
            QueryRecordDO queryResult = queryRecordDao.findByIdAndDeletedFalse(authorizedInfo.getQueryId());
            AssertUtil.assertTrue(!ObjectUtils.isEmpty(queryResult), CheckPersonExceptionEnum.QUERY_RECORD_NOT_EXIST);
            queryResult.setAuthorizedResult(AuthResultType.AUTHORIZING);
            queryRecordDao.save(queryResult);
            // 校验授权记录
            QueryAuthorizationDO queryAuthorization = queryAuthorizationDao
                    .findFirstByQueryIdAndExpiresTimeGreaterThanEqualAndDeletedFalseOrderByCreateTimeDesc(
                            queryResult.getId(), currentTime
                    );
            if (ObjectUtils.isEmpty(queryAuthorization)) {
                queryAuthorizationDao.deleteByQueryId(queryResult.getId());
                res = startCertify(null, authorizedInfo, queryResult.getCreatorId(), currentTime, null, sign);
            } else {
                res = startCertify(queryAuthorization.getCertifyId(), authorizedInfo, queryResult.getCreatorId(), currentTime, null, sign);
            }
        } else {
            AuthInfoDO authInfo = authInfoDao.findAuthInfoByIdAndDeletedFalse(authorizedInfo.getQueryId());
            AssertUtil.assertTrue(!ObjectUtils.isEmpty(authInfo), AuthExceptionEnum.AUTH_NOT_EXIST);
            res = startCertify(null, authorizedInfo, authInfo.getCreatorId(), currentTime, authInfo, sign);
        }

        return StrUtil.isBlank(res) ? "" : res;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean getVerifyResult(String sign) {
        if (StringUtils.isBlank(sign)) {
            log.info("获取签名异常，签名为空！！！");
            return true;
        }

        // 获取查询记录
        AuthorizedInfoDTO authorizedInfo = JSON.parseObject(Sm2Util.decrypt(sign), AuthorizedInfoDTO.class);
        if (!AuthType.REGISTER.equals(authorizedInfo.getAuthType())) {
            QueryRecordDO queryResult = queryRecordDao.findByIdAndDeletedFalse(authorizedInfo.getQueryId());
            AssertUtil.assertTrue(!ObjectUtils.isEmpty(queryResult), CheckPersonExceptionEnum.QUERY_RECORD_NOT_EXIST);
            // 获取授权记录
            QueryAuthorizationDO queryAuthorization = queryAuthorizationDao
                    .findFirstByQueryIdAndDeletedFalseOrderByCreateTimeDesc(queryResult.getId());
            AssertUtil.assertTrue(!ObjectUtils.isEmpty(queryAuthorization), CheckPersonExceptionEnum.QUERY_AUTHORIZATION_NOT_EXIST);
            Timestamp currentTime = new Timestamp(System.currentTimeMillis());
            if (queryAuthorization.getExpiresTime() == null || queryAuthorization.getExpiresTime().before(currentTime)) {
                log.info("查询记录：{}-{} 人脸核身单据号认证超时", queryResult.getId(), queryAuthorization.getCertifyId());
            }
            String certifyResult = queryCertifyResult(queryAuthorization.getCertifyId());
            log.info("认证结果:{}", certifyResult);
            Boolean res = false;
            queryAuthorization.setResult(certifyResult);
            if (StrUtil.isNotBlank(certifyResult)) {
                JSONObject jsonObject = JSONObject.parseObject(certifyResult);
                // 我们需要获取 alipay_user_certify_open_query_response 下的值
                JSONObject queryResponse = jsonObject.getJSONObject("datadigital_fincloud_generalsaas_face_certify_query_response");
                //这里需要注意认证通过的条件 官方文档显示 passed 是个数组，但是它只是一个 String
                if (StrUtil.equals(queryResponse.getString("code"), "10000") && StrUtil.equals(queryResponse.getString("passed"), "T")) {
                    res = true;
                } else {
                    res = false;
                }
            }
            queryAuthorization.setPassed(res);
            queryAuthorizationDao.save(queryAuthorization);
            if (Boolean.TRUE.equals(res)) {
                queryResult.setAuthorizedResult(AuthResultType.AUTHORIZED);
                queryResult.setAuthorizedTime(currentTime);
                queryRecordDao.save(queryResult);
                //增加授权通知 @20240706
                AuthSmsLogDO authSmsLog = authSmsLogDao.findInfoByQueryId(authorizedInfo.getQueryId());
                if(authSmsLog == null){
                    Long queryId = authorizedInfo.getQueryId();
                    QueryRecordDO query = queryRecordDao.findByIdAndDeletedFalse(queryId);
                    AccountDO accountDO = accountDao.findByIdAndDeletedFalse(query.getCreatorId());
                    String phone = userInfoDao.findByIdAndDeletedFalse(accountDO.getUserId()).getPhone();
                    String cxr = accountDO.getUsername();
                    String bcxr = JSONObject.parseObject(query.getContent()).getString("name");
                    smsService.sendAuthSuccess(phone, cxr, bcxr);
                    //支付宝小程序查他人授权成功，证明该交易结束，需要对可能存在的推荐码以及邀请人进行积分
                    if (query.getOrigin().equals(EndpointType.ALIPAY_APPLET)) {
                        VipOrderDO vipOrderDO = vipOrderDao.findOrderByTradeNoAndDeletedFalse(query.getTradeNo());
                        operatorService.updateHistoryScore(vipOrderDO);
                    }
                    authSmsLog = new AuthSmsLogDO();
                    authSmsLog.setQueryId(queryId);
                    authSmsLog.setCreateTime(currentTime);
                    authSmsLogDao.save(authSmsLog);
                }
            }
            return res;
        } else {
            AuthInfoDO authInfo = authInfoDao.findAuthInfoByIdAndDeletedFalse(authorizedInfo.getQueryId());
            AssertUtil.assertTrue(!ObjectUtils.isEmpty(authInfo), AuthExceptionEnum.AUTH_NOT_EXIST);
            Timestamp currentTime = new Timestamp(System.currentTimeMillis());
            if (authInfo.getExpiresTime() == null || authInfo.getExpiresTime().before(currentTime)) {
                log.info("认证记录：{}-{} 人脸核身单据号认证超时", authInfo.getId(), authInfo.getCertifyId());
            }
            String certifyResult = queryCertifyResult(authInfo.getCertifyId());
            log.info("认证结果:{}", certifyResult);
            Boolean res = false;
            authInfo.setResult(certifyResult);
            if (StrUtil.isNotBlank(certifyResult)) {
                JSONObject jsonObject = JSONObject.parseObject(certifyResult);
                // 我们需要获取 alipay_user_certify_open_query_response 下的值
                JSONObject queryResponse = jsonObject.getJSONObject("datadigital_fincloud_generalsaas_face_certify_query_response");
                //这里需要注意认证通过的条件 官方文档显示 passed 是个数组，但是它只是一个 String
                if (StrUtil.equals(queryResponse.getString("code"), "10000") && StrUtil.equals(queryResponse.getString("passed"), "T")) {
                    res = true;
                } else {
                    res = false;
                }
            }
            authInfo.setPassed(res);
            authInfo.setAuthorizedTime(currentTime);

            OrganizationDO organization = organizationDao.findByIdAndDeletedFalse(authInfo.getRelativeId());
            AssertUtil.assertTrue(!ObjectUtils.isEmpty(organization), OrganizationExceptionEnum.ORGANIZATION_NOT_EXIST);
            if (Boolean.TRUE.equals(res)) {
                // 个人直接校验成功
                if (OrganizationType.SINGLE.equals(organization.getType())) {
                    organization.setAuthState(AuthState.PASS);
                } else {
                    // 企业进入企业信息校验
                    String orgResult = openService.getOrgInfo(organization);
                    log.info("企业认证结果:{}", orgResult);

                    if (StringUtils.isNotBlank(orgResult)) {
                        authInfo.setOrgResult(orgResult);

                        JsonObject object = GSON.fromJson(orgResult, JsonObject.class);
                        if (!ObjectUtils.isEmpty(object.get("error_code")) && "0".equals(object.get("error_code").getAsString())
                                && !ObjectUtils.isEmpty(object.get("result"))) {
                            JsonObject result = object.get("result").getAsJsonObject();
                            if (!ObjectUtils.isEmpty(result.get("companyName")) && organization.getEnterName().equals(result.get("companyName").getAsString())
                                    && !ObjectUtils.isEmpty(result.get("faRen")) && organization.getUsername().equals(result.get("faRen").getAsString())
                            ) {
                                organization.setAuthState(AuthState.PASS);
                            }
                        }
                    }
                }
            } else {
                organization.setAuthState(AuthState.NOT_PASS);
            }
            authInfoDao.save(authInfo);
            organizationDao.save(organization);

            return res;
        }
    }

    @Override
    public CheckPersonReportVO getPersonalReport(String sign) {
        if (StringUtils.isBlank(sign)) {
            log.info("获取签名异常，签名为空！！！");
            return new CheckPersonReportVO();
        }
        SmsRecordDO smsRecord = smsRecordDao.findByRemarksAndDeletedFalse(sign);
        AssertUtil.assertTrue(!ObjectUtils.isEmpty(smsRecord), SmsExceptionEnum.SMS_RECORD_NOT_EXIST);
        AssertUtil.assertTrue((smsRecord.getExpiresTime().getTime() >= System.currentTimeMillis()), SmsExceptionEnum.SMS_REPORT_EXPIRED);
        AuthorizedInfoDTO authorizedInfo = JSON.parseObject(smsRecord.getContent(), AuthorizedInfoDTO.class);
        return checkPersonService.getReport(smsRecord.getCreatorId(), new GetQueryInfoForm(authorizedInfo.getQueryId()));
    }

    /**
     * 初始化身份认证
     */
    public String authInitialize(AuthorizedInfoDTO authorizedInfo, Long userId, Timestamp currentTime, AuthInfoDO authInfo, String sign) {
        DatadigitalFincloudGeneralsaasFaceCertifyInitializeRequest request = new DatadigitalFincloudGeneralsaasFaceCertifyInitializeRequest();

        //构造身份信息json对象  JSONObject 阿里的fastjson
        JSONObject identityObj = new JSONObject();
        //身份类型，必填
        identityObj.put("identity_type", "CERT_INFO");
        //证件类型，必填
        identityObj.put("cert_type", "IDENTITY_CARD");
        //真实姓名，必填
        identityObj.put("cert_name", authorizedInfo.getName());
        //证件号码，必填
        identityObj.put("cert_no", authorizedInfo.getIdNumber());
        //手机号，选填
        identityObj.put("phone_no", authorizedInfo.getPhone());
        //构造商户配置json对象
        JSONObject merchantConfigObj = new JSONObject();
        try {
//            merchantConfigObj.put("return_url", "http://47.100.124.208:8902/#/pages/index/result");
//            merchantConfigObj.put("return_url", "http://47.100.124.208:8902/#/pages/index/result?sign=" + sign);
//            merchantConfigObj.put("return_url", "https://cxb.learncoder.com/#/pages/index/result?sign=" + sign);
            merchantConfigObj.put("return_url", "https://admin.njxnet.com/face/#/pages/index/result?sign=" + sign);

            //构造身份认证初始化服务业务参数数据
            JSONObject bizContentObj = new JSONObject();
            //商户请求的唯一标识，推荐为uuid，必填  IdUtil hutool工具
            bizContentObj.put("outer_order_no", IdUtil.simpleUUID());
            bizContentObj.put("biz_code", "FUTURE_TECH_BIZ_FACE_SDK");
            bizContentObj.put("identity_param", identityObj);
            bizContentObj.put("merchant_config", merchantConfigObj);
            request.setBizContent(bizContentObj.toString());

            //发起请求
            DatadigitalFincloudGeneralsaasFaceCertifyInitializeResponse response = alipayClient.execute(request);

            if (response.isSuccess()) {
                log.info("[身份验证]初始化身份认证成功:{}", authorizedInfo.getName());
                //接口调用成功，从返回对象中获取certify_id
                String certifyId = response.getCertifyId();
                log.info("生成的certifyId:{}", certifyId);
                // 生成的certifyId 是查询认证结果的凭证，需要保存下来
                if (ObjectUtils.isEmpty(authInfo)) {
                    QueryAuthorizationDO queryAuthorization = new QueryAuthorizationDO();
                    queryAuthorization.setQueryId(authorizedInfo.getQueryId());
                    queryAuthorization.setCertifyId(certifyId);
                    queryAuthorization.setExpiresTime(new Timestamp(currentTime.getTime() + 23 * 60 * 60 * 1000));
                    queryAuthorization.setCreatorId(userId);
                    queryAuthorizationDao.save(queryAuthorization);
                } else {
                    authInfo.setCertifyId(certifyId);
                    authInfo.setExpiresTime(new Timestamp(currentTime.getTime() + 23 * 60 * 60 * 1000));
                    authInfoDao.save(authInfo);
                }

                return certifyId;
            } else {
                log.info("[身份验证]初始化身份认证失败:{}", authorizedInfo.getName());
                return null;
            }
        } catch (Exception e) {
            log.error("[身份验证]初始化身份认证失败:{}", authorizedInfo.getName(), e);
            return null;
        }
    }

    /**
     * 开始认证服务调用
     */
    public String startCertify(String existCertifyId, AuthorizedInfoDTO authorizedInfo, Long userId, Timestamp currentTime, AuthInfoDO authInfo, String sign) {
        String certifyId = StrUtil.isBlank(existCertifyId) ? authInitialize(authorizedInfo, userId, currentTime, authInfo, sign) : existCertifyId;
        if (StrUtil.isBlank(certifyId)) {
            return null;
        }

        DatadigitalFincloudGeneralsaasFaceCertifyVerifyRequest request = new DatadigitalFincloudGeneralsaasFaceCertifyVerifyRequest();
        //设置certifyId
        JSONObject bizContentObj = new JSONObject();
        bizContentObj.put("certify_id", certifyId);
        request.setBizContent(bizContentObj.toString());

        //生成请求链接，这里一定要使用GET模式
        try {
            DatadigitalFincloudGeneralsaasFaceCertifyVerifyResponse response = alipayClient.execute(request);
            if (response.isSuccess()) {
                log.info("[身份验证]开始认证服务调用成功:{}", authorizedInfo.getName());
                log.info("身份认证成果结果:{}", response.getBody());
                return response.getCertifyUrl();
            } else {
                log.info("[身份验证]开始认证服务调用失败:{}", authorizedInfo.getName());
                return null;
            }
        } catch (AlipayApiException e) {
            log.error("[身份验证]开始认证服务调用失败:{}", authorizedInfo.getName(), e);
            return null;
        }
    }

    /**
     * 查询身份认证结果
     *
     * @param certifyId 需要你在你的业务中获取之前保存下来的 certify_id
     */
    public String queryCertifyResult(String certifyId) {
        DatadigitalFincloudGeneralsaasFaceCertifyQueryRequest request = new DatadigitalFincloudGeneralsaasFaceCertifyQueryRequest();
        JSONObject bizContentObj = new JSONObject();
        bizContentObj.put("certify_id", certifyId);
        request.setBizContent(bizContentObj.toString());
        try {
            DatadigitalFincloudGeneralsaasFaceCertifyQueryResponse response = alipayClient.execute(request);
            if (response.isSuccess()) {
                log.info("[身份验证]认证查询服务调用成功:{}", certifyId);
                // 返回的是个json字符串
                return response.getBody();
            } else {
                log.info("[身份验证]认证查询服务调用失败:{}", certifyId);
            }
        } catch (AlipayApiException e) {
            log.error("[身份验证]开始认证服务调用失败:{}", certifyId, e);
        }
        return null;
    }

}
